#include <stdio.h>
 
//  指针是一个变量，其值为另一个变量的地址，即，内存位置的直接地址。就像其他变量或常量一样，
// 您必须在使用指针存储其他变量地址之前，对其进行声明。
int main ()
{
    int  var = 20;   /* 实际变量的声明 */
    int  *ip;        /* 指针变量的声明 */
    char ch = 's';
    char *zch;
    zch = &ch;
    
    ip = &var;  /* 在指针变量中存储 var 的地址 */
    // ip = var;  指针是不可以这样赋值的
    *ip = 10;  // 可以这样赋值，但其实是改变了内存地址的值，也就是是对 var 的内存地址进行赋值
    // 也就是说 *ip在c语言中就是取地址，下面的输出实例，恰恰证明了 *ip就是得到指针变量的地址

    int  *ptr = NULL;
    
    printf("ptr 的地址是 %p\n", ptr  );
    
    printf("Address of var variable: %p\n", &var  );
    
    /* 在指针变量中存储的地址 */
    printf("Address stored in ip variable: %p\n", ip );
    
    /* 使用指针访问值 */
    printf("Value of *ip variable: %d\n", *ip );
    // printf("Value of *ip variable: %d\n", ip ); // 为什么这样会报错

    printf("%d \n", *zch);  // 取指针变量的数字码 也是对应的ASCII码值
    // printf("%c \n", zch); // 将指针以字符输出，错误的做法   后面这个是正确的printf("%c \n", *zch);
    printf("%s \n", zch);   // 访问指针的值和普通变量一致，但是在后面取值时就会报错
    printf("%p \n", zch);   // 注意：只有指针变量可以这样取出地址，换成zh就会报错
    printf("%p \n", &ch);   // 这才是普通变量取地址的方法，可以理解为将这个变量的地址取到，以指针(16进制)输出
    printf("%c \n",ch);     // 这个可以理解为拿到地址内的值以字符型输出
    // 指针变量就是一种变量，存储的值是16进制的内存地址，c语言里面可以取到指针变量的值以及内存地址
    // 使用 *p 实质上就是取到这个指针变量存储的地址的值，可以按照改地址存储的值的形式输出
    // 例子：printf("%c \n", *p) 其中定义的p是一个字符指针变量；所有这里就是将指针存储的地址的值按照字符输出
    // 使用 p ，直接输出 p 实质上就是和其他的输出一样，将这个指针变量输出，因此它只能输出为 %p 16进制的指针类型
    // 例子：printf("%p \n", p) 实质上就是输出p这个变量，只是这个变量有点特殊，需要以 %p 形式来输出

    /*
    %x      将所给存储单元以十六进制形式输出。
    %a(%A)  浮点数、十六进制数字和p-(P-)记数法(C99)
    %c      字符
    %s      字符串
    %d      有符号十进制整数,将所给存储单元以十进制有符号型形式输出。
    %f      浮点数(包括float和doulbe)
    %e(%E)  浮点数指数输出[e-(E-)记数法]
    %g(%G)  浮点数不显无意义的零"0"
    %i      有符号十进制整数(与%d相同)
    %u      无符号十进制整数
    %o      八进制整数    e.g.     0123
    %x(%X)  十六进制整数0f(0F)   e.g.   0x1234
    %p      指针,将所给存储单元以十六进制输出指针变量对应的地址值
    %%      "%"
    */
    return 0;
}